﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Windows.Forms;

namespace DMEditor
{
    public class DM10Instrument
    {
        public string name = "";
        public DM10InstLayer[] instLayers = new DM10InstLayer[2];
        public DM10MIDIInstrument midi = new DM10MIDIInstrument();

        public DM10Instrument()
        {
            for (int i = 0; i < instLayers.Length; ++i) instLayers[i] = new DM10InstLayer();
        }

        public static int[] Size = new int[] { (21 * 2) + 12, (22 * 2) + 20, (22 * 2) + 20 };

        public byte[] Save()
        {
            byte[] data = new byte[Size[DM10ModuleSettings.fileVersion]];
            int ctr = 0;
            int padding = (name.Length >= 12 ? 0 : 12 - name.Length);

            // Copy out the instrument name (only first 12 chars and null-pad if necessary)
            for (ctr = 0; ctr < (name.Length > 12 ? 12 : name.Length); ++ctr) data[ctr] = (byte)name[ctr];
            ctr += padding; // Skip all unused chars, as all bytes are initialized to 0x00 anyhow

            // Now start dumping the instrument data
            for (int layer = 0; layer < 2; ++layer)
            {

                data[ctr++] = instLayers[layer]._category;
                data[ctr++] = BitConverter.GetBytes(instLayers[layer]._sound)[0];
                data[ctr++] = BitConverter.GetBytes(instLayers[layer]._sound)[1];

                data[ctr++] = instLayers[layer]._level;
                data[ctr++] = instLayers[layer]._pan;
                data[ctr++] = instLayers[layer]._decay;
                data[ctr++] = instLayers[layer]._attack;

                data[ctr++] = instLayers[layer]._reverb;
                data[ctr++] = instLayers[layer]._effects;
                data[ctr++] = (byte)instLayers[layer].eq;
                
                data[ctr++] = instLayers[layer]._semitone;
                data[ctr++] = instLayers[layer]._finetune;
                data[ctr++] = instLayers[layer]._filter;
                data[ctr++] = (byte)instLayers[layer].filtertype;
                
                data[ctr++] = instLayers[layer]._velDecay;
                data[ctr++] = instLayers[layer]._velFilter;
                data[ctr++] = instLayers[layer]._velLevel;
                data[ctr++] = instLayers[layer]._velPitch;
                
                data[ctr++] = (byte)instLayers[layer].output;
                data[ctr++] = instLayers[layer]._priority;
                data[ctr++] = instLayers[layer]._muteGroup;
                data[ctr++] = (byte)instLayers[layer].monoPlayback;

                //Program.LogForm.AddLogItem("ctr: " + ctr);
            }


            data[ctr++] = (byte)midi.channel;
            data[ctr++] = (byte)midi.note;
            data[ctr++] = (byte)midi.gateTime;
            data[ctr++] = (byte)midi.sendNoteOff;

            data[ctr++] = (byte)midi.chordMode;
            data[ctr++] = (byte)midi.note2;
            data[ctr++] = (byte)midi.note3;
            data[ctr++] = (byte)midi.note4;

            return data;
        }

        public void LoadVersion0(byte[] data)
        {
            int ctr = 0;

            name = "";
            for (int i = 0; i < 12; ++i)
            {
                if ((char)data[ctr] != '\0')
                    name += (char)(data[ctr]);

                ctr++; // Out here so any NULL chars don't affect the count
            }

            name = name.Trim();

            for (int layer = 0; layer < 2; ++layer)
            {
                instLayers[layer]._category = data[ctr++];

                instLayers[layer].sound = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);

                instLayers[layer]._level = data[ctr++];
                instLayers[layer]._pan = data[ctr++];
                instLayers[layer]._decay = data[ctr++];

                instLayers[layer]._reverb = data[ctr++];
                instLayers[layer]._effects = data[ctr++];
                instLayers[layer].eq = data[ctr++];

                instLayers[layer]._semitone = data[ctr++];
                instLayers[layer]._finetune = data[ctr++];
                instLayers[layer]._filter = data[ctr++];
                instLayers[layer].filtertype = data[ctr++];

                instLayers[layer]._velDecay = data[ctr++];
                instLayers[layer]._velFilter = data[ctr++];
                instLayers[layer]._velLevel = data[ctr++];
                instLayers[layer]._velPitch = data[ctr++];

                instLayers[layer].output = data[ctr++];
                instLayers[layer]._priority = data[ctr++];
                instLayers[layer]._muteGroup = data[ctr++];
                instLayers[layer].monoPlayback = data[ctr++];
            }

        }

        public void LoadVersion1(byte[] data)
        {
            int ctr = 0;

            name = "";
            for (int i = 0; i < 12; ++i)
            {
                if ((char)data[ctr] != '\0')
                    name += (char)(data[ctr]);

                ctr++; // Out here so any NULL chars don't affect the count
            }

            name = name.Trim();

            for (int layer = 0; layer < 2; ++layer)
            {
                instLayers[layer]._category = data[ctr++];

                instLayers[layer].sound = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);

                instLayers[layer]._level = data[ctr++];
                instLayers[layer]._pan = data[ctr++];
                instLayers[layer]._decay = data[ctr++];
                instLayers[layer]._attack = data[ctr++];

                instLayers[layer]._reverb = data[ctr++];
                instLayers[layer]._effects = data[ctr++];
                instLayers[layer].eq = data[ctr++];

                instLayers[layer]._semitone = data[ctr++];
                instLayers[layer]._finetune = data[ctr++];
                instLayers[layer]._filter = data[ctr++];
                instLayers[layer].filtertype = data[ctr++];

                instLayers[layer]._velDecay = data[ctr++];
                instLayers[layer]._velFilter = data[ctr++];
                instLayers[layer]._velLevel = data[ctr++];
                instLayers[layer]._velPitch = data[ctr++];

                instLayers[layer].output = data[ctr++];
                instLayers[layer]._priority = data[ctr++];
                instLayers[layer]._muteGroup = data[ctr++];
                instLayers[layer].monoPlayback = data[ctr++];
            }

            midi.channel = data[ctr++];
            midi.note = data[ctr++];
            midi.gateTime = data[ctr++];
            midi.sendNoteOff = data[ctr++];

            midi.chordMode = data[ctr++];
            midi.note2 = data[ctr++];
            midi.note3 = data[ctr++];
            midi.note4 = data[ctr++];

        }

        public void LoadVersion2(byte[] data)
        {
            // V2 is only a kit-level change, not instruments
            LoadVersion1(data);
        }
    }

    public class DM10InstLayer
    {

#region Variables
        // Sound settings
        public byte _category = 0;
        public short _sound = 0;

        // Levels
        public byte _level = 0;
        public byte _pan = 50; // <0: left, >0 = right
        public byte _decay = 0;
        public byte _attack = 0; // 0-99

        // FX
        public byte _reverb = 0;
        public byte _effects = 0;
        public bool _eq = true; 

        // Tone
        public byte _semitone = 0;
        public byte _finetune = 0;
        public byte _filter = 0;
        public bool _filtertype = false; // false: low-pass, true = high-pass


        // Dynamics
        public byte _velDecay = 0; // +- 99
        public byte _velFilter = 0; // +- 99
        public byte _velLevel = 0; // +- 99
        public byte _velPitch = 0; // +- 99

        // Other settings
        public bool _output = false; // false: main, true: aux
        public byte _priority = 1; // 0: low, 1: med, 2: high
        public byte _muteGroup = 0; // 0: off, 01-09 only
        public bool _monoPlayback = false; // false: poly
#endregion

#region Properties
        public int category 
        {
            get { return _category;}
            set { _category = (byte)value; }
        }

        public int sound
        {
            get { return _sound;}
            set { _sound = (short)value; }
        }

        // Levels
        public int level
        {
            get { return _level; }
            set { _level = (byte)value; }
        }

        public int pan 
        {
            get { return _pan;}
            set { _pan = (byte)value; }
        }

        public int attack
        {
            get { return _attack; }
            set { _attack = (byte)value; }
        }

        public int decay
        {
            get { return _decay; }
            set { _decay = (byte)value; }
        }

        // FX
        public int reverb
        {
            get { return _reverb; }
            set { _reverb = (byte)value; }
        }
        public int effects
        {
            get { return _effects; }
            set { _effects = (byte)value; }
        }

        public int eq
        {
            get { return _eq == false ? 0 : 1; }
            set { _eq = (value == 0 ? false : true); }
        }

        // Tone
        public int semitone
        {
            get { return _semitone - 12;}
            set { _semitone = (byte)(value + 12); }
        }

        public int finetune
        {
            get { return _finetune - 50;}
            set { _finetune = (byte)(value + 50); }
        }

        public int filter
        {
            get { return _filter;}
            set { _filter = (byte)value; }
        }

        public int filtertype
        {
            get { return (_filtertype == false ? 0 : 1); }
            set { _filtertype = (value == 0 ? false : true); }
        }


        // Dynamics
        public int velDecay
        {
            get { return _velDecay - 99; }
            set { _velDecay = (byte)(value + 99); }
        }

        public int velFilter
        {
            get { return _velFilter - 99; }
            set { _velFilter = (byte)(value + 99); }
        }

        public int velLevel
        {
            get { return _velLevel; }
            set { _velLevel = (byte)value; }
        }

        public int velPitch
        {
            get { return _velPitch - 99; }
            set { _velPitch = (byte)(value + 99); }
        }     
        
        
        // Other settings
        public int  output
        {
            get { return (_output == false ? 0 : 1); }
            set { _output = (value == 0 ? false : true); }
        }

        public int priority
        {
            get { return _priority; }
            set { _priority = (byte)value; }
        }

        public int muteGroup
        {
            get { return _muteGroup; }
            set { _muteGroup = (byte)value; }
        }

        public int monoPlayback 
        {
            get { return (_monoPlayback == false ? 0 : 1); }
            set { _monoPlayback = (value == 0 ? false : true); }
        }
        
#endregion

    }


    public class DM10MIDIInstrument
    {
        public short channel = 0; // MIDI channel 
        public short note = 0; //MIDI note
        public short gateTime = 0; //0: off, 01-99 normal, 100+: 1/32, 1/32trplt, 1/16, 1/16trplt, 1/8, 1/8trplt, 1/4, 1/4trplt, 1/2, 1/2trplt
        public short sendNoteOff = 1; // 0: Not sent, 1: sent, 2: alternate

        // Chords
        public short chordMode = 0; // 0: no chords, 1: chord, 2: arpeggio
        public short note2 = -1; // MIDI notes of the other notes in this chord (-1: off)
        public short note3 = -1;
        public short note4 = -1;
    }

    public partial class DM10Kit
    {
        public string name;

        public DM10Instrument[] instruments = new DM10Instrument[21];

        //public static int Size { get { return (DM10Instrument.Size[DM10ModuleSettings.fileVersion] * 22) + 35 + 1; } } // +1: file version
        public static int[] Size = new int[] { (DM10Instrument.Size[DM10ModuleSettings.fileVersion] * 22) + 35 + 1, (DM10Instrument.Size[DM10ModuleSettings.fileVersion] * 22) + 35 + 1, (DM10Instrument.Size[DM10ModuleSettings.fileVersion] * 22) + 35 + 1 };

        public DM10Kit(int currentSoundset)
        {
            for (int i = 0; i < instruments.Length; ++i) instruments[i] = new DM10Instrument();

            setDefaults(currentSoundset);

            createFXOptions();
            createEQFrequencies();

        }


#region Properties
        // Reverb settings
        public short reverbType
        {
            get { return _reverbType; }
            set { _reverbType = (byte)value; }
        }

        public short reverbSize
        {
            get { return _reverbSize; }
            set { _reverbSize = (byte)value; }
        }

        public short reverbColor
        {
            get { return _reverbColor; }
            set { _reverbColor = (byte)value; }
        }

        public short reverbLevel
        {
            get { return _reverbLevel; }
            set { _reverbLevel = (byte)value; }
        }

        // FX settings
        public short fxType
        {
            get { return _fxType; }
            set { _fxType = (byte)value; }
        }

        public short fxRate
        {
            get { return _fxRate; }
            set { _fxRate = (byte)value; }
        }

        public short fxDepth
        {
            get { return _fxDepth; }
            set { _fxDepth = (byte)value; }
        }

        public short fxLevel
        {
            get { return _fxLevel; }
            set { _fxLevel = (byte)value; }
        }

        public short fxDamp
        {
            get { return _fxDamp; }
            set { _fxDamp = (byte)value; }
        }
        public short fxFeedbackL
        {
            get { return _fxFeedbackL; }
            set { _fxFeedbackL = (byte)value; }
        }

        public short fxFeedbackR
        {
            get { return _fxFeedbackR; }
            set { _fxFeedbackR = (byte)value; }
        }

        public short fxDelayL
        {
            get { return _fxDelayL; }
            set { _fxDelayL = value; }
        }

        public short fxDelayR
        {
            get { return _fxDelayR; }
            set { _fxDelayR = value; }
        }

        // Compression
        public short compType
        {
            get { return _compType; }
            set { _compType = (byte)value; }
        }

        public short compLevel 
        {
            get { return _compLevel; }
            set { _compLevel = (byte)value; }
        }
        public short compOutLevel
        {
            get { return (short)(_compOutLevel - 24); }
            set { _compOutLevel = (byte)(value + 24); }
        }

        // EQ settings
        public int eqLFGain
        {
            get { return _eqLFGain - 60; }
            set { _eqLFGain = (short)(value + 60); }
        }

        public int eqLFFreq
        {
            get { return _eqLFFreq; }
            set { _eqLFFreq = (short)value; }
        }

        public int eqHFGain
        {
            get { return _eqHFGain - 60; }
            set { _eqHFGain = (short)(value + 60); }
        }

        public int eqHFFreq
        {
            get { return _eqHFFreq; }
            set { _eqHFFreq = (short)value; }
        }
#endregion

#region Variables
        // Reverb settings
        protected byte _reverbType = 12; // 0: off, 12: RmSmlDrk, 22 max
        protected byte _reverbSize = 71;
        protected byte _reverbColor = 57;
        protected byte _reverbLevel = 99;

        // FX settings
        protected byte _fxType = 1;
        protected byte _fxRate = 28;
        protected byte _fxDepth = 70;
        protected byte _fxLevel = 99;
        protected byte _fxDamp = 99;
        protected byte _fxFeedbackL = 88; // percent
        protected byte _fxFeedbackR = 88; // percent
        protected short _fxDelayL = 50; // ms
        protected short _fxDelayR = 50; // ms

        // Compression
        protected byte _compType = 14; // 0: off, TODO: Enum
        protected byte _compLevel = 1; // Max 30
        protected byte _compOutLevel = 27; // +- 24dB

        // EQ settings
        protected short _eqLFGain = 15; 
        protected short _eqLFFreq = 15; 
        protected short _eqHFGain = 15; 
        protected short _eqHFFreq = 68; 

#endregion


        static public int[] EnabledFXOptions = new int[18]; // Which FX options should be enabled based on FX type?
        static public string[] EQFrequencies = new string[100];

        public enum FXOptions
        {
            FXLevel = (1 << 0),
            FXDepth = (1 << 1),
            FXDamp = (1 << 2),
            FXRate = (1 << 3),
            FXFeedbackL = (1 << 4),
            FXFeedbackR = (1 << 5),
            FXDelayL = (1 << 6),
            FXDelayR = (1 << 7)
        }

        static private void createFXOptions()
        {
            EnabledFXOptions[0] = 0; // None disables all options
            EnabledFXOptions[1] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[2] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[3] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[4] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[5] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[6] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[7] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXFeedbackL | FXOptions.FXLevel);
            EnabledFXOptions[8] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXLevel);
            EnabledFXOptions[9] =  (int)(FXOptions.FXRate | FXOptions.FXDepth | FXOptions.FXLevel);
            EnabledFXOptions[10] =  (int)(FXOptions.FXDelayL | FXOptions.FXLevel);
            EnabledFXOptions[11] =  (int)(FXOptions.FXDelayL | FXOptions.FXLevel);
            EnabledFXOptions[12] =  (int)(FXOptions.FXDelayL | FXOptions.FXLevel);
            EnabledFXOptions[13] =  (int)(FXOptions.FXDelayL | FXOptions.FXLevel);
            EnabledFXOptions[14] =  (int)(FXOptions.FXDelayL | FXOptions.FXFeedbackL | FXOptions.FXDamp | FXOptions.FXLevel);
            EnabledFXOptions[15] =  (int)(FXOptions.FXDelayL | FXOptions.FXDelayR | FXOptions.FXFeedbackL | FXOptions.FXFeedbackR | FXOptions.FXDamp | FXOptions.FXLevel);
            EnabledFXOptions[16] =  (int)(FXOptions.FXDelayL | FXOptions.FXDelayR | FXOptions.FXFeedbackL | FXOptions.FXDamp | FXOptions.FXLevel);
            EnabledFXOptions[17] =  (int)(FXOptions.FXDelayL | FXOptions.FXFeedbackL | FXOptions.FXDamp | FXOptions.FXLevel);
        }

        static private void createEQFrequencies()
        {
            EQFrequencies[0] = "20 Hz";
            EQFrequencies[1] = "22 Hz";
            EQFrequencies[2] = "24 Hz";
            EQFrequencies[3] = "26 Hz";
            EQFrequencies[4] = "28 Hz";
            EQFrequencies[5] = "32 Hz";
            EQFrequencies[6] = "36 Hz";
            EQFrequencies[7] = "40 Hz";
            EQFrequencies[8] = "44 Hz";
            EQFrequencies[9] = "50 Hz";
            EQFrequencies[10] = "58 Hz";
            EQFrequencies[11] = "66 Hz";
            EQFrequencies[12] = "76 Hz";
            EQFrequencies[13] = "86 Hz";
            EQFrequencies[14] = "98 Hz";
            EQFrequencies[15] = "110 Hz";
            EQFrequencies[16] = "120 Hz";
            EQFrequencies[17] = "140 Hz";
            EQFrequencies[18] = "160 Hz";
            EQFrequencies[19] = "180 Hz";
            EQFrequencies[20] = "210 Hz";
            EQFrequencies[21] = "230 Hz";
            EQFrequencies[22] = "260 Hz";
            EQFrequencies[23] = "290 Hz";
            EQFrequencies[24] = "320 Hz";
            EQFrequencies[25] = "360 Hz";
            EQFrequencies[26] = "400 Hz";
            EQFrequencies[27] = "440 Hz";
            EQFrequencies[28] = "490 Hz";
            EQFrequencies[29] = "530 Hz";
            EQFrequencies[30] = "580 Hz";
            EQFrequencies[31] = "640 Hz";
            EQFrequencies[32] = "700 Hz";
            EQFrequencies[33] = "760 Hz";
            EQFrequencies[34] = "820 Hz";
            EQFrequencies[35] = "890 Hz";
            EQFrequencies[36] = "970 Hz";
            EQFrequencies[37] = "1.0 kHz";
            EQFrequencies[38] = "1.1 kHz";
            EQFrequencies[39] = "1.2 kHz";
            EQFrequencies[40] = "1.3 kHz";
            EQFrequencies[41] = "1.4 kHz";
            EQFrequencies[42] = "1.5 kHz";
            EQFrequencies[43] = "1.6 kHz";
            EQFrequencies[44] = "1.7 kHz";
            EQFrequencies[45] = "1.8 kHz";
            EQFrequencies[46] = "1.9 kHz";
            EQFrequencies[47] = "2.0 kHz";
            EQFrequencies[48] = "2.2 kHz";
            EQFrequencies[49] = "2.3 kHz";
            EQFrequencies[50] = "2.4 kHz";
            EQFrequencies[51] = "2.6 kHz";
            EQFrequencies[52] = "2.7 kHz";
            EQFrequencies[53] = "2.9 kHz";
            EQFrequencies[54] = "3.0 kHz";
            EQFrequencies[55] = "3.2 kHz";
            EQFrequencies[56] = "3.4 kHz";
            EQFrequencies[57] = "3.6 kHz";
            EQFrequencies[58] = "3.8 kHz";
            EQFrequencies[59] = "4.0 kHz";
            EQFrequencies[60] = "4.2 kHz";
            EQFrequencies[61] = "4.4 kHz";
            EQFrequencies[62] = "4.6 kHz";
            EQFrequencies[63] = "4.8 kHz";
            EQFrequencies[64] = "5.0 kHz";
            EQFrequencies[65] = "5.3 kHz";
            EQFrequencies[66] = "5.5 kHz";
            EQFrequencies[67] = "5.8 kHz";
            EQFrequencies[68] = "6.0 kHz";
            EQFrequencies[69] = "6.3 kHz";
            EQFrequencies[70] = "6.6 kHz";
            EQFrequencies[71] = "6.9 kHz";
            EQFrequencies[72] = "7.2 kHz";
            EQFrequencies[73] = "7.5 kHz";
            EQFrequencies[74] = "7.8 kHz";
            EQFrequencies[75] = "8.1 kHz";
            EQFrequencies[76] = "8.4 kHz";
            EQFrequencies[77] = "8.7 kHz";
            EQFrequencies[78] = "9.1 kHz";
            EQFrequencies[79] = "9.4 kHz";
            EQFrequencies[80] = "9.8 kHz";
            EQFrequencies[81] = "10.2 kHz";
            EQFrequencies[82] = "10.5 kHz";
            EQFrequencies[83] = "10.9 kHz";
            EQFrequencies[84] = "11.3 kHz";
            EQFrequencies[85] = "11.7 kHz";
            EQFrequencies[86] = "12.1 kHz";
            EQFrequencies[87] = "12.6 kHz";
            EQFrequencies[88] = "13.0 kHz";
            EQFrequencies[89] = "13.4 kHz";
            EQFrequencies[90] = "13.9 kHz";
            EQFrequencies[91] = "14.4 kHz";
            EQFrequencies[92] = "14.8 kHz";
            EQFrequencies[93] = "15.3 kHz";
            EQFrequencies[94] = "15.8 kHz";
            EQFrequencies[95] = "16.3 kHz";
            EQFrequencies[96] = "16.9 kHz";
            EQFrequencies[97] = "17.4 kHz";
            EQFrequencies[98] = "17.9 kHz";
            EQFrequencies[99] = "18.5 kHz";
        }

        public byte[] Save(byte version)
        {
            byte[] data = new byte[Size[DM10ModuleSettings.fileVersion]]; 

            int ctr = 1;

            data[0] = version;

            int padding = (name.Length >= 12 ? 0 : 12 - name.Length);

            // Copy out the kit name (only first 12 chars and null-pad if necessary)
            for (int i = 0; i < (name.Length > 12 ? 12 : name.Length); ++ctr, ++i) data[ctr] = (byte)name[i];
            ctr += padding; // Skip all unused chars, as all bytes are initialized to 0x00 anyhow


            // Now dump the kit FX settings
            data[ctr++] = (byte)_reverbType;
            data[ctr++] = (byte)_reverbSize;
            data[ctr++] = (byte)_reverbColor;
            data[ctr++] = (byte)_reverbLevel;

            data[ctr++] = (byte)_fxType;
            data[ctr++] = (byte)_fxLevel;
            data[ctr++] = (byte)_fxDepth;
            data[ctr++] = (byte)_fxDamp;
            data[ctr++] = (byte)_fxRate;
            data[ctr++] = (byte)_fxFeedbackL;
            data[ctr++] = (byte)_fxFeedbackR;
            data[ctr++] = BitConverter.GetBytes(_fxDelayL)[0];
            data[ctr++] = BitConverter.GetBytes(_fxDelayL)[1];
            data[ctr++] = BitConverter.GetBytes(_fxDelayR)[0];
            data[ctr++] = BitConverter.GetBytes(_fxDelayR)[1];

            data[ctr++] = (byte)_compType;
            data[ctr++] = (byte)_compLevel;
            data[ctr++] = (byte)_compOutLevel;

            data[ctr++] = (byte)_eqLFGain;
            data[ctr++] = (byte)_eqLFFreq;
            data[ctr++] = (byte)_eqHFGain;
            data[ctr++] = (byte)_eqHFFreq;            

            // Now dump all the instruments
            for (int i = 0; i < instruments.Length; ++i)
            {
                byte[] inst = instruments[i].Save();

                for (int j = 0; j < inst.Length; ++j) data[ctr++] = inst[j];
            }

            Program.LogForm.AddLogItem("Size is " + Size + ", ctr: " + ctr);

            return data;
        }

        public bool Load(byte[] data)
        {
            if (data.Length == 0)
            {
                MessageBox.Show("Invalid kit data. Please check the file and try again.");
                return false;
            }

            byte version = data[0];

            switch (version)
            {
                case 0:
                    return LoadVersion0(data, version);

                case 1:
                    return LoadVersion1(data, version);

                case 2:
                    return LoadVersion2(data, version);

                default:
                    return false;
            }


        }

        private bool LoadVersion0(byte[] data, byte version)
        {
            int ctr = 1; // Start at 1 to skip version

            try
            {
                // Pull name out of data
                name = "";
                for (int i = 0; i < 12; ++i)
                {
                    if (data[ctr] != '\0')
                        name += (char)(data[ctr]);

                    ctr++; // Out here so any NULL chars don't affect the count
                }

                // Now do kit FX
                _reverbType = data[ctr++];
                _reverbSize = data[ctr++];
                _reverbColor = data[ctr++];
                _reverbLevel = data[ctr++];

                _fxType = data[ctr++];
                _fxLevel = data[ctr++];
                _fxDepth = data[ctr++];
                _fxDamp = data[ctr++];
                _fxRate = data[ctr++];
                _fxFeedbackL = data[ctr++];
                _fxFeedbackR = data[ctr++];
                _fxDelayL = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);
                _fxDelayR = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);

                _compType = data[ctr++];
                _compLevel = data[ctr++];
                _compOutLevel = data[ctr++];

                _eqLFGain = data[ctr++];
                _eqLFFreq = data[ctr++];
                _eqHFGain = data[ctr++];
                _eqHFFreq = data[ctr++];

                // Now read the instruments

                for (int i = 0; i < instruments.Length; ++i)
                {
                    byte[] inst = new byte[DM10Instrument.Size[0]];

                    for (int j = 0; j < inst.Length; ++j) inst[j] = data[ctr++];

                    switch (version)
                    {
                        case 0:
                            instruments[i].LoadVersion0(inst);
                            break;

                        case 1:
                            instruments[i].LoadVersion1(inst);
                            break;


                    }
                }
            }
            catch 
            {
                MessageBox.Show("Error with loading kit. Are you sure this is a .dmk file?");
                return false;
            }

            return true;
        }

        private bool LoadVersion1(byte[] data, byte version)
        {
            int ctr = 1; // Start at 1 to skip version

            try
            {

            // Pull name out of data
            name = "";
            for (int i = 0; i < 12; ++i)
            {
                if (data[ctr] != '\0')
                    name += (char)(data[ctr]);

                ctr++; // Out here so any NULL chars don't affect the count
            }

            // Now do kit FX
            _reverbType = data[ctr++];
            _reverbSize = data[ctr++];
            _reverbColor = data[ctr++];
            _reverbLevel = data[ctr++];

            _fxType = data[ctr++];
            _fxLevel = data[ctr++];
            _fxDepth = data[ctr++];
            _fxDamp = data[ctr++];
            _fxRate = data[ctr++];
            _fxFeedbackL = data[ctr++];
            _fxFeedbackR = data[ctr++];
            _fxDelayL = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);
            _fxDelayR = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);

            _compType = data[ctr++];
            _compLevel = data[ctr++];
            _compOutLevel = data[ctr++];

            _eqLFGain = data[ctr++];
            _eqLFFreq = data[ctr++];
            _eqHFGain = data[ctr++];
            _eqHFFreq = data[ctr++];

            // Now read the instruments

            for (int i = 0; i < instruments.Length; ++i)
            {
                byte[] inst = new byte[DM10Instrument.Size[1]];

                for (int j = 0; j < inst.Length; ++j) inst[j] = data[ctr++];

                switch (version)
                {
                    case 0:
                        instruments[i].LoadVersion0(inst);
                        break;

                    case 1:
                        instruments[i].LoadVersion1(inst);
                        break;


                }
            }

                        }
            catch 
            {
                MessageBox.Show("Error with loading kit. Are you sure this is a .dmk file?");
                return false;
            }

    return true;
        }

        private bool LoadVersion2(byte[] data, byte version)
        {
            int ctr = 1; // Start at 1 to skip version
             
            try
            {

                // Pull name out of data
                name = "";
                for (int i = 0; i < 12; ++i)
                {
                    if (data[ctr] != '\0')
                        name += (char)(data[ctr]);

                    ctr++; // Out here so any NULL chars don't affect the count
                }

                // Now do kit FX
                _reverbType = data[ctr++];
                _reverbSize = data[ctr++];
                _reverbColor = data[ctr++];
                _reverbLevel = data[ctr++];

                _fxType = data[ctr++];
                _fxLevel = data[ctr++];
                _fxDepth = data[ctr++];
                _fxDamp = data[ctr++];
                _fxRate = data[ctr++];
                _fxFeedbackL = data[ctr++];
                _fxFeedbackR = data[ctr++];
                _fxDelayL = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);
                _fxDelayR = BitConverter.ToInt16(new byte[] { data[ctr++], data[ctr++] }, 0);

                _compType = data[ctr++];
                _compLevel = data[ctr++];
                _compOutLevel = data[ctr++];

                _eqLFGain = data[ctr++];
                _eqLFFreq = data[ctr++];
                _eqHFGain = data[ctr++];
                _eqHFFreq = data[ctr++];

                // Now read the instruments

                for (int i = 0; i < instruments.Length; ++i)
                {
                    byte[] inst = new byte[DM10Instrument.Size[version]];

                    for (int j = 0; j < inst.Length; ++j) inst[j] = data[ctr++];

                    switch (version)
                    {
                        case 0:
                            instruments[i].LoadVersion0(inst);
                            break;

                        case 1:
                            instruments[i].LoadVersion1(inst);
                            break;

                        case 2:
                            instruments[i].LoadVersion2(inst);
                            break;
                    }
                }

            }
            catch
            {
                MessageBox.Show("Error with loading kit. Are you sure this is a .dmk file?");
                return false;
            }

            return true;
        }
    }

    public class DM10ModuleSettings
    {
        public const byte fileVersion = 0x02;
        public byte currentSoundset = 0; // 0: stock, 1: BJ
        public DM10Soundset[] soundsets = new DM10Soundset[2];
        public DM10Soundset soundset
        {
            get { return soundsets[currentSoundset]; }
        }

        public DM10Kit[] kits = new DM10Kit[100]; // actual value is 100+idx; the first 100 are static

        public short currentKit = 0; // Index to kits

        public string soundsetName
        {
            get { return (currentSoundset == 0) ? "Stock" : "BlueJay"; }
        }

        public DM10ModuleSettings()
        {
            soundsets[0] = new DM10Soundset(0);
            soundsets[1] = new DM10Soundset(1);


            for (int i = 0; i < kits.Length; ++i) kits[i] = new DM10Kit(currentSoundset);
        }

        public void setDefaults()
        {
            for (int i = 0; i < kits.Length; ++i) kits[i].setDefaults(currentSoundset);
        }

        public void SaveModule(string filename)
        {
            Program.LogForm.AddLogItem("Saving module to " + filename);
            BinaryWriter file = new BinaryWriter(new FileStream(filename, FileMode.Create));

            file.Write(Program.settings.currentSoundset);

            for (int kitid = 0; kitid < 100; ++kitid) file.Write(kits[kitid].Save(fileVersion));

            file.Close();

            Program.MainForm.setTitle(filename);

        }

        public void LoadModule(string filename)
        {
            BinaryReader file = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)); 
            byte[] data;

            Program.settings.currentSoundset = file.ReadByte();
            setDefaults();

            for (int i = 0; i < 100; ++i)
            {
                data = file.ReadBytes(DM10Kit.Size[DM10ModuleSettings.fileVersion]);

                kits[i].Load(data);
            }

            Program.MainForm.setTitle(filename);
        }

        public void SaveKit(string filename, int kitID)
        {
            Program.LogForm.AddLogItem("Saving kit " + kitID + " to " + filename);

            BinaryWriter file = new BinaryWriter(new FileStream(filename, FileMode.Create));

            file.Write(kits[kitID].Save(fileVersion));

            file.Close();

        }
        
        public void LoadKit(string filename, int kitID)
        {
            Program.LogForm.AddLogItem("Loading kit " + kitID + " from " + filename);

            BinaryReader file = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read));
            byte[] data = file.ReadBytes(DM10Kit.Size[DM10ModuleSettings.fileVersion]);
            file.Close();

            bool ret = kits[kitID].Load(data);

            if (ret == true) Program.module.UploadKit(kitID);

        }

        public void SaveInstrument(string filename, int kitID, int instrumentID)
        {
            Program.LogForm.AddLogItem("Saving instrument " + instrumentID + " in kit " + kitID + " to " + filename);

            BinaryWriter file = new BinaryWriter(new FileStream(filename, FileMode.Create));

            file.Write(fileVersion);
            file.Write(kits[kitID].instruments[instrumentID].Save());


            file.Close();
        }

        public void LoadInstrument(string filename, int kitID, int instrumentID)
        {
            Program.LogForm.AddLogItem("Loading instrument " + instrumentID + " in kit " + kitID + " from " + filename);

            BinaryReader file = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read));

            byte version = file.ReadByte();
            if (version > DM10ModuleSettings.fileVersion)
            {
                MessageBox.Show("Invalid instrument data! Was this file created in a newer version?");
                return;
            }

            byte[] data = data = file.ReadBytes(DM10Instrument.Size[version]);

            switch (version)
            {
                case 0:
                    kits[kitID].instruments[instrumentID].LoadVersion0(data);
                    break;

                case 1:
                    kits[kitID].instruments[instrumentID].LoadVersion1(data);
                    break;

                case 2:
                    kits[kitID].instruments[instrumentID].LoadVersion2(data);
                    break;
            }


            file.Close();

            Program.module.UploadInstrument(kitID, instrumentID);
        }


    }


 
}
